<?php

namespace App\Jobs;

use App\Constant;
use App\Enums\TransferStatus;
use App\Exceptions\ApiException;
use App\Models\AgentConfig;
use App\Models\TransferRecord;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Arr;

class HezhiTradeNotifyJob implements ShouldQueue
{
    use Dispatchable;
    use InteractsWithQueue;
    use Queueable;
    use SerializesModels;

    /** @var TransferRecord */
    private $record;

    private $retry = 0;

    private $delaySeconds = [5, 10, 30, 60, 60 * 5, 60 * 60];

    /**
     * Create a new job instance.
     *
     * @param mixed $retry
     */
    public function __construct(TransferRecord $record, $retry = 0)
    {
        $this->record = $record;
        $this->retry = $retry;
    }

    /**
     * Execute the job.
     */
    public function handle()
    {
        $record = $this->record->fresh();
        if ($record->status->isNot(TransferStatus::SUCCESS())) {
            return;
        }
        $sourceParams = json_decode($record->source_params, true);
        $notifyUrl = Arr::get($sourceParams, 'return_url');
        if (!$notifyUrl) {
            return;
        }
        $this->notify($notifyUrl, $record);
    }

    /** 交易回调 */
    private function notify($url, TransferRecord $record)
    {
        $token = $this->getToken();
        $asset = $record->asset;
        $data = [
            'buy_account' => $record->to_user->wallet_address,
            'sell_account' => $asset->user->wallet_address,
            'commodity_code' => $asset->contract_address,
            'certificate_code' => $asset->token_id,
            'certificate_number' => $asset->cert_sn,
            'trade_chain_code' => $record->transfer_sn,
            'status' => 0,
            'note' => '',
            'token' => $token,
        ];
        \Log::channel(Constant::LOG_CHANNEL_HEZHI)->info('[OUT] TRADE_NOTIFY(' . $this->retry . '): ' . $url, $data);
        $resp = \Http::asJson()->post($url, $data);
        \Log::channel(Constant::LOG_CHANNEL_HEZHI)->info('[OUT] TRADE_NOTIFY_RESP: ' . $resp->body());
        $retCode = $resp->json('code');
        if (is_null($retCode) || '0' != $retCode) {
            \Cache::delete($this->getTokenCacheKey());
            $delay = Arr::get($this->delaySeconds, $this->retry);
            if ($delay) {
                self::dispatch($record, $this->retry + 1)->delay($delay);
            } else {
                throw new ApiException('notify failed after ' . $this->retry . ' retries');
            }
        }
    }

    /** 获取token */
    private function getToken()
    {
        return \Cache::remember($this->getTokenCacheKey(), 30 * 60, function () {
            $host = config('services.hezhi.host');
            $key = AgentConfig::getConfig($this->record->agent_id, AgentConfig::HEZHI_KEY);

            $url = $host . '/apigateway/cr-adapter/token/getToken';
            $data = ['key' => $key];
            \Log::channel(Constant::LOG_CHANNEL_HEZHI)->info('[OUT] GET_TOKEN: ' . $url, $data);
            $resp = \Http::asJson()->post($url, $data);
            \Log::channel(Constant::LOG_CHANNEL_HEZHI)->info('[OUT] GET_TOKEN_RESP: ' . $resp->body());

            return $resp->json('value');
        });
    }

    private function getTokenCacheKey()
    {
        return 'hezhi_notify_token_' . $this->record->agent_id;
    }
}
